package com.example.java_gobang.api;

import com.example.java_gobang.game.Matcher;
import com.example.java_gobang.game.OnlineUserManager;
import com.example.java_gobang.model.User;
import com.example.java_gobang.tools.Constant;
import com.example.java_gobang.tools.MatchRequest;
import com.example.java_gobang.tools.MatchResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-08-16
 * Time: 9:21
 */
//处理匹配功能中的 websocket 请求
@Component
public class MatchAPI extends TextWebSocketHandler {
    //维护用户状态、目的是在代码中比较方便的获取到某个用户当前的 websocket 会话从而可以通过这个会话给这个客户端发送消息
    //同时也可以感知他 在线/离线 状态 使用哈希表保存用户的在线状态 key 用户 id value 是当前用户使用的会话
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private Matcher matcher;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //连接之后 代表用户上线

        //1、先获取到 用户信息 是谁上线了
        //可以使用到 session 全靠注册 websocket 时候加上的 .addInterceptors(new HttpSessionHandshakeInterceptor());
        //这个逻辑 把 httpsession 中的 session 全部都拿到了 WebSocketSession 中
        //此处的用户可能为空 用户直接通过 url 来访问
        try{
            User user = (User) session.getAttributes().get(Constant.USERINFO_SESSION_KEY);
            //先判断当前用户是否已经登录过

            if(onlineUserManager.getFromGameHall(user.getUserId()) != null
                    || onlineUserManager.getFromGameRoom(user.getUserId()) != null){
                //当前用户不为空 已经登录 需要告知客户端重复登录
                MatchResponse matchResponse = new MatchResponse();
                matchResponse.setOk(true);
                matchResponse.setMessage("ToMany");
                matchResponse.setReason("禁止多开");

                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
//                session.close();
                return;
            }
            //2、拿到了身份信息之后，就可以把玩家信息设置为在线状态
            onlineUserManager.enterGameHall(user.getUserId(),session);
            System.out.println(user.getUsername() + "进入游戏大厅");
        }catch (NullPointerException e){
            System.out.println("当用尚未登录");
            //出现空指针异常 当前用户身份信息未登录
            MatchResponse matchResponse = new MatchResponse();
            matchResponse.setOk(false);
            matchResponse.setReason("尚未登录");
            //先转换为 json 字符串 再包装上一层TextMessage进行传输 文本格式 websocket 数据报
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //处理匹配和停止匹配信息

        User user = (User) session.getAttributes().get(Constant.USERINFO_SESSION_KEY);

        //获取到客户端发送给服务器的数据
        String playLoad = message.getPayload();

        MatchRequest request = objectMapper.readValue(playLoad, MatchRequest.class);

        MatchResponse matchResponse = new MatchResponse();

        if(request.getMessage().equals("startMatch")){
            //创建匹配队列
            matcher.add(user);
            matchResponse.setOk(true);
            matchResponse.setMessage("startMatch");
        }else if(request.getMessage().equals("stopMatch")){
            //退出匹配队列
            matcher.remove(user);
            matchResponse.setOk(true);
            matchResponse.setMessage("stopMatch");
        }else{
            //非法情况
            matcher.remove(user);
            matchResponse.setOk(false);
            matchResponse.setReason("非法的匹配");
        }

        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //发生异常 代表用户下线

        try{
            User user = (User) session.getAttributes().get(Constant.USERINFO_SESSION_KEY);

            WebSocketSession socketSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(socketSession == session){
                //退出和登录的是一个人
                onlineUserManager.exitGameHall(user.getUserId());
                System.out.println(user.getUsername() + "退出游戏大厅");
            }

            //如果玩家正在匹配中 连接断开了 就应该移除匹配
            matcher.remove(user);
        }catch (NullPointerException e){
            System.out.println("当用尚未登录");
            //出现空指针异常 当前用户身份信息未登录
//            MatchResponse matchResponse = new MatchResponse();
//            matchResponse.setOk(false);
//            matchResponse.setReason("尚未登录");
//            //先转换为 json 字符串 再包装上一层TextMessage进行传输 文本格式 websocket 数据报
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //连接关闭之后 代表用户下线
        try{
            User user = (User) session.getAttributes().get(Constant.USERINFO_SESSION_KEY);
            WebSocketSession socketSession = onlineUserManager.getFromGameHall(user.getUserId());
            if(socketSession == session){
                //退出和登录的是一个人
                onlineUserManager.exitGameHall(user.getUserId());
                System.out.println(user.getUsername() + "退出游戏大厅");
            }
            //如果玩家正在匹配中 连接断开了 就应该移除匹配
            matcher.remove(user);
        }catch (NullPointerException e){
            System.out.println("当用尚未登录");
            //出现空指针异常 当前用户身份信息未登录
//            MatchResponse matchResponse = new MatchResponse();
//            matchResponse.setOk(false);
//            matchResponse.setReason("尚未登录");
//            //先转换为 json 字符串 再包装上一层TextMessage进行传输 文本格式 websocket 数据报
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
        }
    }
}
